const { Router } = require('express');
const { createUpload } = require('../utils/file');
const { check, checkStudentGet } = require('../utils/valitate');
// 从fs/promises中导入的函数都是支持promise的
const { unlink } = require('fs/promises');
const fs = require('fs');
const query = require('../utils/query');
const { videoLog } = require("../utils/log");

const router = Router();
const upload = createUpload('upload/video');

router.use(checkStudentGet);

router.route('/')
    .post(  // 添加视频
        upload.single('video'), // 处理上传的文件
        check([], ['course_id', 'name']),// 校验参数
        async (req, res) => {
            try {
                // 文件的校验
                if (!req.file) return res.send({
                    code: 0,
                    msg: '请上传视频'
                });
                // 判断文件类型是否匹配
                if (!req.file.mimetype.startsWith('video')) {
                    // 删除不匹配的资源
                    await unlink(req.file.path);
                    return res.send({
                        code: 0,
                        msg: "请上传正确的视频"
                    });
                }
                // 数据库的存储
                const { name, course_id } = req.body;
                const sql = `INSERT INTO video (name,url,course_id) values (?,?,?)`;
                // 执行sql
                await query(sql, [name, req.file.path, course_id]);
                res.send({
                    code: 1,
                    msg: "保存成功"
                });
            } catch (error) {
                // 删除已上传的资源
                unlink(req.file.path);
                res.send({
                    code: 0,
                    msg: "保存失败"
                });
            }
        }
    )
    .get(   // 获取视频列表
        check(['id'], []),
        async (req, res) => {
            try {
                // 根据课程的id进行视频的查询，并根据名称进行排序
                const sql = `SELECT Id,name FROM video WHERE course_id=? ORDER BY name`;
                const data = await query(sql, [req.query.id]);
                // 响应数据
                res.send({
                    code: 1,
                    data
                });
            } catch (error) {
                console.log(error);
                res.send({
                    code: 0,
                    msg: '获取失败'
                });
            }
        }
    )
    .put(   // 修改视频
        upload.single('video'), // 处理上传的文件
        check(['id'], []),  // 校验必须要在路径上拼接视频id
        async (req, res) => {
            try {
                // 先查询之前的数据（赋默认值）
                const sql1 = `SELECT name,url FROM video WHERE Id=?`;
                let data = await query(sql1, [req.query.id]);
                // 如果没有查询到数据
                if (data.length === 0) {
                    // 如果上传有视频，需要将视频删除
                    if (req.file) unlink(req.file.path);
                    return res.send({
                        code: 0,
                        msg: "没找到该数据"
                    });
                }
                // 取出查询到的数据
                data = data[0];
                // 取值，并赋默认值（如果不传则保持原数据）
                const name = req.body.name || data.name;
                const url = req.file?.path || data.url;
                // 拼接sql
                const sql2 = `UPDATE video SET name=?,url=? WHERE Id=?`;
                // 执行sql
                await query(sql2, [name, url, req.query.id]);
                // 如果上传了视频，修改操作完成之后将旧视频删除
                if (req.file) unlink(data.url);
                res.send({
                    code: 1,
                    msg: '修改成功'
                });
            } catch (error) {
                console.log(error);
                res.send({
                    code: 0,
                    msg: '修改失败'
                });
            }
        }
    )
    .delete(    // 删除视频
        check(['id'], []),
        async (req, res) => {
            try {
                // 1、先查询视频的地址
                let url = await query(`SELECT url FROM video WHERE id=?`, [req.query.id]);
                url = url[0].url;
                // 拼接sql进行删除操作
                const sql = `DELETE FROM video WHERE id=?`;
                // 执行sql
                await query(sql, [req.query.id]);
                // 删除视频
                unlink(url);
                res.send({
                    code: 1,
                    msg: "删除成功"
                });
            } catch (error) {
                console.log(error);
                res.send({
                    code: 0,
                    msg: "删除失败"
                });
            }
        }
    );

// 根据视频id获取视频
router.get(
    '/get-video',
    check(['id'], []),   // 参数校验
    async (req, res) => {
        // 1、先查询视频的地址
        let url = await query(`SELECT url FROM video WHERE id=?`, [req.query.id]);
        url = url[0]?.url || 'upload/not-found.mp4';

        videoLog(req.userInfoLaoGuo.Id, req.query.id);

        // 2、响应视频
        // 1 sendFile用于响应文件资源，(先将整个文件资源读取出来，然后全部响应给客户端)
        // 参数为文件路径（绝对路径）
        // path.resolve(url)    转换参数为绝对路径
        // res.sendFile(path.resolve(url));

        // 2 响应视频流stream 读取文件流
        // 以流的方式读取文件，并响应给客户端(使用video标签请求资源会导致无法快进)
        // fs.ReadStream(url).pipe(res);

        // 3 分段视频流
        let range = req.headers.range;
        // 请求头中有range头才使用分段加载
        if (range) {
            // 1、根据路径读取文件信息
            const stat = fs.statSync(url);
            // 记录文件总大小
            const fileSize = stat.size;
            // 2、根据请求头的range读取对应文件片段
            const parts = range.replace('bytes=', '').split('-');
            const start = parseInt(parts[0]);  // 计算从哪里开始读取文件
            // 计算读取文件到哪里，单位 1MB = 1024KB；1KB=1024字节
            let end = parts[1] ?  // 如果要求了要哪些资源
                parseInt(parts[1])  // 就读取到哪些资源
                :
                start + 2 * 1024 * 1024;    // 否则从开始的位置往后读取5MB

            // 对end要进行判断，不能读超过了
            end = end < fileSize - 1 ? end : fileSize - 1;

            // 3、读取文件流,
            // 参数2：配置对象
            const stream = fs.createReadStream(url, {
                start: start,   // 开始读取的位置
                end: end        // 结束读取的位置
            });

            // 4、设置响应头
            res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);

            // 5、设置响应码为206
            res.status(206);

            // 6、响应当前读取的视频流
            stream.pipe(res);
        } else {
            fs.createReadStream(url).pipe(res);
        }
    }
)


module.exports = router;
